# -*- coding: utf-8 -*-  
#!/usr/bin/python2.7
"""博客业务与数据操作的接口Services

只要在pages.py和admin/pages.py时对页面数据增删改请求等业务时调用
"""

__authors__ = [
  '"BigYuki" <sheyuqi@gmail.com>',
]

from core.files import StaticFile
from core.caches import Cache
from core.sessions import Session
from core.models import Administrator,Archive,Article,Blog
from core.models import Category,Comment,Navigation,Tag,TagRelationship
from core.services.OauthService import FlickrOauthService
from core.flickr import FlickrAPI


class DataService(object):
    def exist(self,*args,**kw):
        assert 0,'exist must be defined'
    def get(self,*args,**kw):
        assert 0,'get must be defined'
    def all(self,*args,**kw):
        assert 0,'all must be defined'
    def put(self,*args,**kw):
        assert 0,'put must be defined'
    def update(self,*args,**kw):
        assert 0,'update must be defined'
    def delete(self,*args,**kw):
        assert 0,'delete must be defined'
    
class DataServiceFactory:
    @staticmethod
    def ImageServiceInstance():
        return ImageService()
    @staticmethod
    def AdminServiceInstance():
        return AdministratorService()
    @staticmethod
    def CommentServiceInstance():
        return CommentService()
    @staticmethod
    def ArchiveServiceInstance():
        return ArchiveService()
    @staticmethod
    def BlogServiceInstance():
        return BlogService()
    @staticmethod
    def CategroyServiceInstance():
        return CategoryService()
    @staticmethod
    def ArticleServiceInstance():
        return ArticleService()
    @staticmethod
    def TagServiceInstance():
        return TagService()
    @staticmethod
    def TagRelationshipServiceInstance():
        return TagRelationshipService()
    @staticmethod
    def NavigationServiceInstance():
        return NavigationService()
    @staticmethod
    def FileServiceInstance():
        return FileService()

class FileService(DataService):
    def get(self,filePath):
        file=Cache(filePath).get()
        if file:
                return file.read()
        else:
            file = StaticFile(filePath)
            Cache(filePath).set(file)
            return file.read()

class ImageService(DataService):
    def delete(self,photoID):
        flickrOauth=FlickrOauthService.GetFlickrOauth()
        return FlickrAPI.DeletePhoto(flickrOauth, photoID)
    def all(self):
        flickrOauth=FlickrOauthService.GetFlickrOauth()
        return FlickrAPI.GetPhotoList(flickrOauth.userID)

    def put(self,fileInput=None):
        """ 上传FileInput这个图片 成功返回 URL 失败返回None """
        flickrOauth=FlickrOauthService.GetFlickrOauth()
        return self.get(FlickrAPI.Upload(fileInput, flickrOauth))
    
    def get(self,photoID):
        return FlickrAPI.GetPhoto(photoID)

class CommentService(DataService):
    """管理Comment这个data model。
    
    为Article文章回复提供业务接口。
    """
    def put(self,articleID=None,nickname=None,email=None,website=None,content=None,ip=None):
        article=Article.get_by_id(articleID)
        article.commenttimes+=1
        article.put()  
        newComment=Comment(
                           article=article,
                           isBloger=False,
                           nickname=nickname,
                           email=email,
                           website=website,
                           content=content,
                           ip=ip
                           )
        return newComment.put()

    def get(self,articleID=None):
        if(articleID!=None):
            article=Article.get_by_id(articleID)   
            return Comment.all().filter("article =", article).order("-time")
        else:
            return None

class NavigationService(DataService):
    def __init__(self):
        self.__topCache=Cache('navigationList')
        self.__sideCache=Cache('linkList')
    def update(self,navigationID=None,name=None,link=None,weight=None,position='TOP'):
        navigation=Navigation.get_by_id(navigationID)
        navigation.name=name
        navigation.link=link
        navigation.weight=weight
        navigation.position=position
        self.__topCache.delete()
        self.__sideCache.delete()
        return navigation.put() 
    
    def put(self,name=None,link=None,weight=None,position='TOP'):
        navigation= Navigation(
                               name=name,
                               link=link,
                               weight=weight,
                               position=position,
                               )
        self.__topCache.delete()
        self.__sideCache.delete()
        return navigation.put()
     
    def delete(self,id):
        try:
            Navigation.get_by_id(id).delete()
            return True
        except:
            return False
     
    def get(self,link=None,navigationID=None):
        if navigationID!=None:
            return Navigation.get_by_id(navigationID)
        elif link!=None:
            return Navigation.all().filter("link =", link).get()
     
    def all(self,position=None):
        """获取数据库中Navigation的多条记录#已缓存"""
        if position=='TOP':
            navigationList=self.__topCache.get()
            if navigationList:
                return navigationList
            else:           
                navigationList=Navigation.all().filter('position =', 'TOP').order('weight')
                self.__topCache.set(navigationList)
                return navigationList
        elif position=='SIDE':
            linkList=self.__sideCache.get()
            if linkList:
                return linkList
            else:           
                linkList=Navigation.all().filter('position =', 'SIDE').order('weight')
                self.__sideCache.set(linkList)
                return linkList
        else:
            return Navigation.all().order('weight')


class TagRelationshipService(DataService):
     
    def put(self,articleKey,tagsKeyList):
        result=True
        for tagKey in tagsKeyList:
            newRelationship=TagRelationship(
                                           article=articleKey,
                                           tag=tagKey)
            newRelationship.put()
            result=newRelationship.is_saved()
        return result

class TagService(DataService):
    def __init__(self):
        self.__cache=Cache('tagList')
     
    def exist(self,tagName):
        return None!=Tag.all().filter('name =', tagName).get()
     
    def get(self,tagName):
        return Tag.all().filter('name =', tagName).get()
     
    def all(self):
        """获取数据库中Tag的多条记录#已缓存"""
        tagList=self.__cache.get()
        if tagList:
            return tagList
        else:           
            tagList=Tag.all() 
            self.__cache.set(tagList)
            return tagList

     
    def put(self,tagStr):
        """通过字符串向数据库插入数据"""
        tagStr="".join(tagStr.split())
        tagsList=tagStr.split(',') 
        resultList=[]
        for tagsItem in tagsList:
            if tagsItem=='':continue
            result=Tag.all().filter('name = ', tagsItem).get()
            if result==None:
                newTag=Tag(name=tagsItem)
                tagKey=newTag.put()
            else:
                tagKey=result.key()
            try:
                resultList.index(tagKey)
            except:
                resultList.append(tagKey)
        self.__cache.delete()#删除缓存
        return resultList

class AdministratorService(DataService):
     
    def exist(self):
        """判断是否存在一条数据"""
        if Administrator.all().count()>0:
            return True
        else:
            return False
        
    def update(self,username,password):
        admin=self.get()
        admin.username=username
        admin.password=password
        return admin.put()
    
    def put(self,username,password):
        if self.exist():
            return self.get()
        else:
            import md5
            newAdministrator=Administrator(
                                           username=username,
                                           password='%s' % md5.new(password).hexdigest()
                                           )
            return newAdministrator.put()
    def get(self):
        if self.exist():
            return Administrator.all().fetch(limit=1)[0]
        else:
            return None  
    
    def logined(self):
        if Session('user').get():
            return Session('user').get()['loggedin']
        else:
            return False

    def login(self,username,password):
        if self.verify(username, password):
            Session('user').set({'loggedin': True,})
            return True
        else:
            return False
     
    def verify(self,username,password):
        result=Administrator.all().filter('username = ',username).filter('password = ',password).get()
        if result==None:
            return False
        else:
            return True
     
    def logout(self):
        Session('user').delete()
        return True

            
class BlogService(DataService):
    def __init__(self):
        self.__cache=Cache('blog')
    def update(self, name=None,title=None,subtitle=None,theme=None,bloger=None,email=None,description=None
               ,keywords=None,announcement=None,pageSize=10):
        blog=self.get()
        blog.name=name
        blog.title=title
        blog.subtitle=subtitle
        blog.theme=theme
        blog.bloger=bloger
        blog.emai=email
        blog.description=description
        blog.keywords=keywords
        blog.announcement=announcement
        blog.pageSize=pageSize
        self.__cache.delete()
        return blog.put()

    def put(self, name=None,title=None,subtitle=None,bloger=None,email=None,description=None,keywords=None,announcement=None,pageSize=10):
        if self.exist():
            return self.get().key()
        else:
            newBlog=Blog(
                     name=name,
                     title=title,
                     subtitle=title,
                     bloger=bloger,
                     email=email,
                     theme=u"Regal",
                     description=description,
                     keywords=keywords,
                     announcement=announcement,
                     pageSize=pageSize)
            self.__cache.delete()
            return newBlog.put()
        
    def get(self):
        """获取博客数据，没有的话，自动执行首次安装。#已缓存"""
        blog=self.__cache.get()
        if blog:
            return blog
        else: 
            if self.exist():
                blog=Blog.all().fetch(limit=1)[0]
                self.__cache.set(blog)
                return blog
            else:
                self.firstInstall()
                return self.get()
     
    def exist(self):
        """判断数据库是否有数据"""
        if Blog.all().count()>0:
            return True
        else:
            return False
     
    def firstInstall(self):
        """首次安装博客安装"""
        #博客基本信息设置
        import settings

        self.put(
                     name=settings.BlogName,
                     title=settings.BlogTitle,
                     subtitle=settings.BlogSubtitle,
                     bloger=settings.BlogBloger,
                     email=settings.BlogEmail,
                     description=settings.BlogDescription,
                     announcement=settings.BlogAnnouncement,
                     keywords=settings.BlogKeywords,
                     pageSize=settings.BlogPageSize
                     )
        #博客账号密码
        DataServiceFactory.AdminServiceInstance().put(settings.Username, settings.Password)
        #生成默认分类
        categoryID=DataServiceFactory.CategroyServiceInstance().put(u"默认").id()
        #生成关于个人信息的文章
        title=settings.AboutAticleTitle
        shortlink=settings.AboutAticleShortlink
        content=settings.AboutAticleContent
        DataServiceFactory.ArticleServiceInstance().put(
                                                        title=title, 
                                                        shortlink=shortlink, 
                                                        content=content, 
                                                        categoryID=categoryID)
        #生成'关于'导航
        name=title
        link=shortlink
        weight=9
        DataServiceFactory.NavigationServiceInstance().put(name=name, link=link, weight=weight)
        
    def deleteallCache(self):
        """删除所有缓存"""
        pass

class CategoryService(DataService):
    def __init__(self):
        self.__cache=Cache('caegoryList')
        
    def update(self,categoryID=None,name=None):
        category=self.get(categoryID=categoryID)
        category.name=name
        self.__cache.delete()
        return category.put()
    
    def exist(self,categoryName):
        return self.get(categoryName=categoryName)!=None
    
    def put(self,categoryName):
        if self.exist(categoryName):
            return self.get(categoryName=categoryName).key()
        else:
            newCategory=Category(name=categoryName)
            self.__cache.delete()
            return newCategory.put()
    
    def all(self):
        """获取数据库中Category的多条记录#已缓存"""
        categoryList=self.__cache.get()
        if categoryList:
            return categoryList
        else:           
            categoryList=Category.all()
            self.__cache.set(categoryList)
            return categoryList

     
    def get(self,categoryID=None,categoryName=None):
        if categoryID!=None:
            return Category.get_by_id(categoryID)
        elif categoryName!=None:
            return Category.all().filter('name =', categoryName).get()
    def delete(self,id):
        try:
            Category.get_by_id(id).delete()
            return True
        except:
            return False

class ArchiveService(DataService):
    def __init__(self):
        self.__cache=Cache('archiveList')
    
     
    def exist(self,year,month):
        return None!=Archive.all().filter('year = ', year).filter('month = ', month).get()
     
    def get(self,year,month):
        return Archive.all().filter('year = ', year).filter('month = ', month).get()
     
    def put(self,theTime=None):
        if theTime==None:
            from core.filters import TimeFilter
            import datetime
            theTime=TimeFilter.ToLocalTime(datetime.datetime.now())
        result=Archive.all().filter('year = ', theTime.year).filter('month = ', theTime.month).get()
        if result==None:
            newArchive=Archive(year=theTime.year,month=theTime.month)
            result=newArchive.put()
            self.__cache.delete()
            return result
        else:
            return result.key()
     
    def all(self):
        """获取数据库中Archive的多条记录。#已缓存"""
        archiveList=self.__cache.get()
        if archiveList:
            return archiveList
        else:         
            archiveList=Archive.all()
            self.__cache.set(archiveList)
            return archiveList
     
    def delete(self,id):
        try:
            Archive.get_by_id(id).delete()
            return True
        except:
            return False

class ArticleService(DataService):
    def __init__(self):
        self.__cache=Cache('articleList')   
    def update(self,
                                articleID=None,
                                title=None,
                                shortlink=None,
                                content=None,
                                display=True,
                                commentEnable=True,
                                categoryID=None):
        article=self.get(articleID=articleID)
        article.title=title
        article.permalink=u'/%s/%s/%s.html' % (article.archive.year,article.archive.month,title)
        article.shortlink=shortlink
        article.content=content
        article.display=display
        article.commentEnable=commentEnable
        article.category=Category.get_by_id(categoryID)
        article.image=self.getImageLabel(content)
        article.summary=self.summarize(content)
        self.__cache.delete()
        return article.put()

    def put(self,title=None,
                            shortlink=None,
                            content=None,
                            categoryID=None,
                            tagStr=None,
                            display=True,
                            commentEnable=True
                            ):
        category=Category.get_by_id(categoryID)
        archive=Archive.get_by_id(
                                  DataServiceFactory.ArchiveServiceInstance().put().id())
        
        permalink=u'/%s/%s/%s.html' % (archive.year,archive.month,title)
        image=self.getImageLabel(content)
        summary=self.summarize(content)
        newArticle=Article(
                           title=title,
                           permalink=permalink,
                           shortlink=shortlink,
                           content=content,
                           display=display,
                           commentEnable=commentEnable,
                           category=category,
                           archive=archive.key(),
                           summary=summary,
                           image=image
                           )
        articleKey=newArticle.put()
        if tagStr!=None:
            tagsKeyList=DataServiceFactory.TagServiceInstance().put(tagStr)
            DataServiceFactory.TagRelationshipServiceInstance().put(articleKey, tagsKeyList)
        self.__cache.delete()
        return articleKey

    def exist(self,link): 
        exis1= None!=Article.all().filter('permalink =', link).get() 
        exis2= None!=Article.all().filter('shortlink =', link).get() 
        return exis1 or exis2
    
    def getByCategory(self,categoryName):
        return Article.all().filter(
                                            'category =', 
                                            DataServiceFactory.CategroyServiceInstance().get(categoryName=categoryName)
                                            ).order('-creadtedTime')
    def getByDate(self,year,month):
        return Article.all().filter(
                                        'archive =', 
                                        DataServiceFactory.ArchiveServiceInstance().get(year,month)
                                        ).order('-creadtedTime')
    def getByTag(self,tagName):
        tag=DataServiceFactory.TagServiceInstance().get(tagName)
        return tag.getArticles()
    def getByLink(self,link):
        """通过连接获取文章,并把viewtimes+1"""
        if self.exist(link):
            article=Article.all().filter('permalink =', link).get()
            if article==None:
                article=Article.all().filter('shortlink =', link).get()
            article.viewtimes+=1
            article.put()
            return article
        else:
            return None
        
    def get(self,
                                articleID=None,
                                link=None,
                                categoryName=None,
                                year=None,month=None,
                                tagName=None):
        if articleID!=None:
            return Article.get_by_id(articleID)
        elif link!=None:
            return self.getByLink(link)
        elif categoryName!=None:
            return self.getByCategory(categoryName)
        elif year!=None and month!=None:
            return self.getByDate(year, month)
        elif tagName!=None:
            return self.getByTag(tagName)
     
    def all(self):
        """获取数据库中Archive的多条记录。#已缓存"""
        articleList=self.__cache.get()
        if articleList:
            return articleList
        else:         
            articleList=Article.all().order('-creadtedTime')
            self.__cache.set(articleList)
            return articleList
     
    def delete(self,id):
        try:
            Article.get_by_id(id).delete()
            return True
        except:
            return False
    
     
    def getImageLabel(self,str):
        """获取img标签的src中的地址"""
        import re
        regEx_image=r"<img[^>]+>"
        compile=re.compile(regEx_image,re.I)
        result=compile.search(str)
        #首先获取img标签
        if result:
            regEx_image_src=r"""src=('|")[^(\s)]+('|")"""
            src_compile=re.compile(regEx_image_src,re.I)
            src_result=src_compile.search(result.group())
            #获取src标签
            if src_result:
                regEx_image_src_string=r"""('|")[^(\s)]+('|")"""
                string_compile=re.compile(regEx_image_src_string,re.I)
                string_result=string_compile.search(src_result.group())
                #获取string标签
                if string_result:
                    regEx_ImageSrcStr=r"""[^('|")]+"""
                    imageSrcStr_compile=re.compile(regEx_ImageSrcStr,re.I)
                    imageSrcStr_result=imageSrcStr_compile.search(string_result.group())
                    if imageSrcStr_result:
                        return imageSrcStr_result.group()
                    else:
                        return None
                else:
                    return None
            else:
                return None
        else:
            return None
     
    def summarize(self,str):
        import re
        regEx_script = u"<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>"
        regEx_style = u"<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>"
        regEx_html = u"<[^>]+>"
        regEx_houhtml = u"/[^>]+>"
        regEx_table = u"\t+"
        regEx_enter = u"\n+"
        regEx_blank = u"\s+"
        compile=re.compile(regEx_script)
        str=compile.sub(u"",str)
        compile=re.compile(regEx_style)
        str=compile.sub(u"",str)
        compile=re.compile(regEx_html)
        str=compile.sub(u"",str)
        compile=re.compile(regEx_houhtml)
        str=compile.sub(u"",str)
        compile=re.compile(regEx_blank)
        str=compile.sub(u" ",str)
        compile=re.compile(regEx_table)
        str=compile.sub(u"",str)
        compile=re.compile(regEx_enter)
        str=compile.sub(u"  ",str)
        if len(str)>300:
            return str[0:300]
        else:
            return str